package com.warm.base.design.b_memento;


import com.warm.base.design.b_memento.black.BCaretaker;
import com.warm.base.design.b_memento.black.BOriginator;
import com.warm.base.design.b_memento.mult.MCaretaker;
import com.warm.base.design.b_memento.mult.MOriginator;
import com.warm.base.design.b_memento.self.ISMemento;
import com.warm.base.design.b_memento.self.SOriginator;
import com.warm.base.design.b_memento.white.WCaretaker;
import com.warm.base.design.b_memento.white.WOriginator;

/**
 * @Date: 2019/11/27 16:57
 * @Author: LChuang
 * @Description: 备忘录模式(快照模式)
 *
 *      在不破坏封装性的前提下，捕获一个对象的内部状态，并在该对象之外保存这个状态。
 *      这样以后就可将该对象恢复到原先保存的状态
 */
public class Client {

    /**
     * Originator (发起人): 负责创建一个备忘录,可以记录、恢复自身的内部状态。同时Originator还可以根据需要决定Memento存储自身的那些内部状态。
     * Memento (备忘录): 备忘录角色，用于存储Originator的内部状态，并且可以防止Originator以外的对象访问Memento。
     * Caretaker(负责人): 负责存储备忘录，不能对备忘录的内容进行操作和访问，只能够将备忘录传递给其他对象。
     */
    /**
     * 1. 窄接口：
     *     只允许它把备忘录对象传给其他的对象。针对的是负责人对象和其他除发起人对象之外的任何对象。
     *
     * 2. 宽接口:
     *     允许它读取所有的数据，以便根据这些数据恢复这个发起人对象的内部状态。针对发起人。
     */
    public static void main(String[] args) {

        /**
         * 1. 白箱模式: 将发起人角色的状态存储在一个大家都看得到的地方，
         *            备忘录角色的内部所存储的状态就对所有对象公开。
         */
        // 初始状态
        WOriginator wo = new WOriginator();
        wo.setState("state-1");
        System.out.println(wo);

        // 下一步
        WCaretaker wc = new WCaretaker();
        wc.setMemento(wo.createMemento());
        wo.setState("state-2");
        System.out.println(wo);

        // 上一步
        wo.restoreMemento(wc.getMemento());
        System.out.println(wo);

        /**
         * 2. 黑箱模式: 备忘录角色对发起人（Originator）角色对象提供一个宽接口，
         *            而为其他对象提供一个窄接口。这样的实现叫做“黑箱实现”。
         *            简单说就是备忘录是一个接口，实现类放到发起人里面去了，外界看不见。
         */
        BOriginator bo = new BOriginator();
        BCaretaker bc = new BCaretaker();
        // 改变负责人对象的状态
        bo.setState("state-A");
        System.out.println("saving: " + bo);
        // 创建备忘录, 并将发起人对象状态存储起来
        bc.saveMemento(bo.createBMemento());
        // 修改发起人对象的状态
        bo.setState("state-B");
        System.out.println("set new value: " + bo);
        // 恢复发起人对象状态
        bo.restoreBMemento(bc.retrieveBMemento());
        System.out.println("restore: " + bo);

        /**
         * 3. 多重检查点: 常见的系统往往需要存储不止一个状态，而是需要存储多个状态，
         *              或者叫做有多个检查点。用list或者map存储，这种叫做多重检查点
         */
        MOriginator mo = new MOriginator();
        MCaretaker mc = new MCaretaker(mo);
        // change state
        mo.setState("state-10");
        // build memento 建立一个检查点
        mc.createMMemento();
        // change state
        mo.setState("state-11");
        // build memento
        mc.createMMemento();
        // change state
        mo.setState("state-12");
        // build memento
        mc.createMMemento();
        // change state
        mo.setState("state-13");
        // build memento
        mc.createMMemento();
        // print all memento
        mo.printStates();
        // restore memento
        mc.restoreMMemento(1);
        // print all memento
        mo.printStates();

        /**
         * 4. 自述历史模式: 发起人角色自己兼任负责人角色。
         */
        SOriginator so = new SOriginator();
        // change state
        so.setState("state-a");
        System.out.println(so);
        // create memento 创建备忘录
        ISMemento sm = so.createSMemento();
        // change state
        so.setState("state-b");
        System.out.println(so);
        // restore state 按照备忘录恢复对象的状态
        so.restoreSMemento(sm);
        System.out.println(so);
        //4500 3000 2000 3000
    }
}
